package org.xbl.xchain.sdk.gateway.init;

import com.moandjiezana.toml.Toml;
import com.moandjiezana.toml.TomlWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xbl.xchain.sdk.gateway.init.BaseGatewayConfig.AppChain;
import org.xbl.xchain.sdk.gateway.init.BaseGatewayConfig.HubChain;
import org.xbl.xchain.sdk.gateway.init.BaseGatewayConfig.Log;
import org.xbl.xchain.sdk.gateway.init.BaseGatewayConfig.Module;
import org.xbl.xchain.sdk.utils.ErrorMsg;
import org.xbl.xchain.sdk.utils.XcdUtil;

import java.beans.IntrospectionException;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;

public class GatewayToml {
    public static final String Xchain = "xchain";
    public static final String Fabric = "fabric";

    private static final Logger LOGGER = LoggerFactory.getLogger(GatewayToml.class);

    public static final String GatewayLog = "log";
    public static final String GatewayModule = "module";
    public static final String GatewayAppChain = "app-chain";
    public static final String GatewayHubChain = "hub-chain";
    public HashMap<String,Object> GatewayObj2ConfigMap;

    private String title;

    public GatewayToml() {
        GatewayObj2ConfigMap=new HashMap<>();
        this.title="Gateway";
    }

    public GatewayToml(String toml){
        GatewayObj2ConfigMap = (HashMap<String, Object>) new Toml().read(toml).toMap();
    }

    public GatewayToml(String coreChainId,String coreChainNodeIP,String appChainId,String appChainType){
        this.title="Gateway";
        GatewayObj2ConfigMap=new HashMap<>();
        this.setObject2Map(new HubChain(coreChainId,coreChainNodeIP));
        this.setObject2Map(new Log());
        this.setObject2Map(new Module());
        this.setObject2Map(new AppChain(appChainId,appChainType));
    }

    public GatewayToml(HashMap<String, Object> gatewayObj2ConfigMap) {
        this.title="Gateway";
        GatewayObj2ConfigMap = gatewayObj2ConfigMap;
    }

    public void setObject2Map(Object object){
        LOGGER.debug("[{}] set {} into map", ErrorMsg.RootCodespace,object.getClass().getName());
        try{
            String mapName = XcdUtil.CamelToUnderline(object.getClass().getSimpleName(),1,XcdUtil.MidLINE);
            HashMap<String,Object> Obj2ConfigMap2 = new HashMap<String,Object>(){};
            Obj2ConfigMap2 = XcdUtil.ConvertObj2Map(Obj2ConfigMap2,object,XcdUtil.UNDERLINE);
            if(object.getClass()== Module.class){
                HashMap<String,Object> logConfigMap = (HashMap<String,Object>)this.GatewayObj2ConfigMap.get(GatewayLog);
                if (logConfigMap==null){
                    logConfigMap=new HashMap<String,Object>(){};
                }
                logConfigMap.put(mapName,Obj2ConfigMap2);
                mapName=GatewayLog;
                Obj2ConfigMap2=logConfigMap;
            }else if (object.getClass()==Log.class) {
                HashMap<String, Object> logConfigMap = (HashMap<String, Object>) this.GatewayObj2ConfigMap.get(GatewayLog);
                if (logConfigMap != null) {
                    Obj2ConfigMap2.put(GatewayModule, logConfigMap.get(GatewayModule));
                }
            }
            this.GatewayObj2ConfigMap.put(mapName,Obj2ConfigMap2);
        }catch (Exception e){
            LOGGER.error("[{}] set {} to map err : {}", ErrorMsg.RootCodespace,object.getClass().getName(),e.getMessage());
            e.printStackTrace();
        }
    }

    public Object getObjectByKey(String key){
        LOGGER.debug("[{}] get object by map key {} ",ErrorMsg.RootCodespace,key);
        Object object=null;
        Map<String,Object> subMap = null;
        switch (key){
            case GatewayLog:
                object = new Log();
                subMap=(Map<String, Object>) GatewayObj2ConfigMap.get(key);
                break;
            case GatewayModule:
                subMap = (Map<String, Object>) GatewayObj2ConfigMap.get(GatewayLog);
                subMap = (Map<String, Object>) subMap.get(key);
                object = new Module();
                break;
            case GatewayAppChain:
                subMap = (Map<String, Object>) GatewayObj2ConfigMap.get(key);
                object = new AppChain();
                break;
            case GatewayHubChain:
                subMap = (Map<String, Object>) GatewayObj2ConfigMap.get(key);
                object = new HubChain();
                break;
            default:
                return null;
        }
        for (Map.Entry<String, Object> entry : subMap.entrySet()){
            try {
                if (entry.getKey().equals(GatewayLog)||entry.getKey().equals(GatewayAppChain)||
                        entry.getKey().equals(GatewayHubChain)||entry.getKey().equals(GatewayModule)) {
                    continue;
                }
                if (entry.getValue()==null){
                    continue;
                }
                String getMethod;
                getMethod = XcdUtil.UnderlineToCamel(entry.getKey(),1);
//                getMethod="set"+getMethod.substring(0, 1).toUpperCase() + getMethod.substring(1);
                XcdUtil.ExecMethodByName(object,getMethod,entry.getValue());
            } catch (InvocationTargetException | IllegalAccessException | IntrospectionException e) {
                LOGGER.error("[{}] get {} by key err : {}", ErrorMsg.RootCodespace,key,e.getMessage());
                e.printStackTrace();
            }
        }
        return object;
    }

    public String toTomlString(){
        TomlWriter tomlWriter = new TomlWriter();
        this.GatewayObj2ConfigMap.put("title",this.title);
        return tomlWriter.write(this.GatewayObj2ConfigMap);
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }
}
